home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CD ROM Paradise Collection 4
/
CD ROM Paradise Collection 4 1995 Nov.iso
/
program
/
tjgold.zip
/
INSTALL.001
/
DFBTREE.INC
next >
Wrap
Text File
|
1995-07-19
|
35KB
|
949 lines
{--------------------------------------------------------------------------}
{ Product: TechnoJock's Turbo Toolkit }
{ Version: GOLD }
{ Build: 1.01 }
{ }
{ The index routines used in TTT Gold were developed by Dean Farwell II }
{ and are an adaptation of his excellent TBTREE database tools. }
{ }
{ Copyright 1988-1994 Dean Farwell II }
{ Portions Copyright 1986-1995 TechnoJock Software, Inc. }
{ All Rights Reserved }
{ Restricted by License }
{--------------------------------------------------------------------------}
{********************************}
{ Include: DFBTREE }
{********************************}
(******************************************************************************)
(* *)
(* B T R E E C U R S O R R O U T I N E S *)
(* *)
(*****************************************************************************)
(* This routine will return the logical record associated with the cursor.
If the cursor in not valid, 0 will be returned. *)
function LrNumToReturn(var pg : SinglePage; (* var for speed only *)
var pRec : ParameterRecord (* var for speed only *)
) : LrNumber;
var
lrNum : LrNumber;
begin
if pRec.cursor.valid then
begin
Move(pg[((pRec.cursor.entryNum - 1) * (pRec.vSize + RNSIZE)) + 1],
lrNum,
RNSIZE);
end
else
begin
lrNum := 0;
end;
LrNumToReturn := lrNum;
end; (* end of LrNumToReturn routine *)
(*\*)
(* This routine will set the tree cursor to the front of the index. In
other words, it will point to the first entry in the index. Remember, the
index is ordered by the value of each entry. It will also return the
logical record associated with the first entry in the index. It will
return 0 only if there is no first entry (the index is empty). This
routine should be called if you want to start at the beginning of an index
and want to retrieve logical record numbers in order of entry. *)
function UsingCursorGetFirstLr(iFName : FnString;
var fId : File (* var for speed only *)
) : LrNumber;
var
pRec : ParameterRecord;
pg : SinglePage;
begin
FetchFileParameters(iFName,fId,pRec,SizeOf(pRec));
if BTreeErrorOccurred then Exit;
FetchPage(iFName,fId,pRec.fSNode,pg);
if BTreeErrorOccurred then Exit;
if pg[VCNTLOC] > 0 then
begin
pRec.cursor.prNum := pRec.fSNode;
pRec.cursor.entryNum := 1;
pRec.cursor.valid := TRUE;
end
else
begin
pRec.cursor.valid := FALSE;
end;
SaveFileParameters(iFName,fId,pRec,SizeOf(pRec));
if BTreeErrorOccurred then Exit;
UsingCursorGetFirstLr := LrNumToReturn(pg,pRec);
end; (* end of UsingCursorGetFirstLr routine *)
(*\*)
(* This routine will set the tree cursor to the end of the index. In
other words, it will point to the first entry in the index. Remember, the
index is ordered by the value of each entry. It will also return the
logical record associated with the last entry in the index. It will
return 0 only if there is no last entry (the index is empty). This
routine should be called if you want to start at the end of an index
and want to retrieve logical record numbers in reverse order of entry. *)
function UsingCursorGetLastLr(iFName : FnString;
var fId : File (* var for speed only *)
) : LrNumber;
var
pRec : ParameterRecord;
pg : SinglePage;
prevNode : NodePtrType;
begin
FetchFileParameters(iFName,fId,pRec,SizeOf(pRec));
if BTreeErrorOccurred then Exit;
FetchPage(iFName,fId,pRec.lSNode,pg);
if BTreeErrorOccurred then Exit;
if pg[VCNTLOC] > 0 then
begin
pRec.cursor.prNum := pRec.lSNode;
pRec.cursor.entryNum := pg[VCNTLOC];
pRec.cursor.valid := TRUE;
end
else
begin
Move(pg[PREVLOC],prevNode,RNSIZE);
if prevNode <> NULL then
begin
FetchPage(iFName,fId,prevNode,pg);
if BTreeErrorOccurred then Exit;
pRec.cursor.prNum := prevNode;
pRec.cursor.entryNum := pg[VCNTLOC];
pRec.cursor.valid := TRUE;
end
else
begin
pRec.cursor.valid := FALSE;
end;
end;
SaveFileParameters(iFName,fId,pRec,SizeOf(pRec));
if BTreeErrorOccurred then Exit;
UsingCursorGetLastLr := LrNumToReturn(pg,pRec);
end; (* end of UsingCursorGetLastLr routine *)
(*\*)
(* This routine is the same as UsingCursorAndValueGetLr except that this
routine will set the tree cursor to the location of the first value in the
index which is greater than or equal to paramValue. It will also return
the logical record associated with this entry. It will return 0 if there
is no entry which is greater than or equal to this value. *)
function UsingCursorAndGEValueGetLr(iFName : FnString;
var fId : File; (* var for speed only *)
var paramValue;
partial : Boolean) : LrNumber;
var
pRec : ParameterRecord;
pg : SinglePage;
cnt : Byte; (* used to count number of values *)
bytePtr : PageRange; (* used to keep track of current byte *)
thisNode : NodePtrType;
begin
FetchFileParameters(iFName,fId,pRec,SizeOf(pRec));
if BTreeErrorOccurred then Exit;
thisNode := FindSNode(iFName,fId,pRec.rNode,paramValue,pRec);
if BTreeErrorOccurred then Exit;
FetchPage(iFName,fId,thisNode,pg);
if BTreeErrorOccurred then Exit;
cnt := BinarySearchEntry(pg,paramValue,pRec);
if (cnt <> 0) and (cnt <= pg[VCNTLOC]) then
begin
bytePtr := BytePointerPosition(cnt,pRec.vsize);
pRec.cursor.prNum := thisNode;
pRec.cursor.entryNum := cnt;
pRec.cursor.valid := TRUE;
end
else
begin
pRec.cursor.valid := FALSE;
end;
SaveFileParameters(iFName,fId,pRec,SizeOf(pRec));
if BTreeErrorOccurred then Exit;
UsingCursorAndGEValueGetLr := LrNumToReturn(pg,pRec);
end; (* end of UsingCursorAndGEValueGetLr routine *)
(*\*)
(* This routine will move the cursor to the right one entry and return the
value associated with this entry. It will return 0 if the cursor was not
valid (not pointing to an entry) or if there is no next entry (you are at
end of index). This routine should be called if you want to move the
cursor to the next larger entry from the present cursor position and
retrieve the associated logical record number. This routine should not
normally be used until the cursor has been positioned using one of the
three previous positioning routines. *)
function UsingCursorGetNextLr(iFName : FnString;
var fId : File (* var for speed only *)
) : LrNumber;
var
pRec : ParameterRecord;
pg : SinglePage;
begin
FetchFileParameters(iFName,fId,pRec,SizeOf(pRec));
if BTreeErrorOccurred then Exit;
if pRec.cursor.valid then
begin
FetchPage(iFName,fId,pRec.cursor.prNum,pg);
if BTreeErrorOccurred then Exit;
Inc(pRec.cursor.entryNum);
if pRec.cursor.entryNum > pg[VCNTLOC] then
begin
Move(pg[NEXTLOC],pRec.cursor.prNum,RNSIZE);
if pRec.cursor.prNum = NULL then
begin
pRec.cursor.valid := FALSE;
end
else
begin
FetchPage(iFName,fId,pRec.cursor.prNum,pg);
if BTreeErrorOccurred then Exit;
if pg[VCNTLOC] = 0 then
begin
pRec.cursor.valid := FALSE;
end
else
begin
pRec.cursor.entryNum := 1;
end;
end;
end;
SaveFileParameters(iFName,fId,pRec,SizeOf(pRec));
if BTreeErrorOccurred then Exit;
end;
UsingCursorGetNextLr := LrNumToReturn(pg,pRec);
end; (* end of UsingCursorGetNextLr routine *)
(* This routine will move the cursor to the left one entry and return the
value associated with this entry. It will return 0 if the cursor was not
valid (not pointing to an entry) or if there is no next entry (you are at
end of index). This routine should be called if you want to move the
cursor to the next larger entry from the present cursor position and
retrieve the associated logical record number. This routine should not
normally be used until the cursor has been positioned using one of the
previous positioning routines. *)
function UsingCursorGetPrevLr(iFName : FnString;
var fId : File (* var for speed only *)
) : LrNumber;
var
pRec : ParameterRecord;
pg : SinglePage;
begin
FetchFileParameters(iFName,fId,pRec,SizeOf(pRec));
if BTreeErrorOccurred then Exit;
if pRec.cursor.valid then
begin
FetchPage(iFName,fId,pRec.cursor.prNum,pg);
if BTreeErrorOccurred then Exit;
Dec(pRec.cursor.entryNum);
if pRec.cursor.entryNum = 0 then
begin
Move(pg[PREVLOC],pRec.cursor.prNum,RNSIZE);
if pRec.cursor.prNum = NULL then
begin
pRec.cursor.valid := FALSE;
end
else
begin
FetchPage(iFName,fId,pRec.cursor.prNum,pg);
if BTreeErrorOccurred then Exit;
if pg[VCNTLOC] = 0 then
begin
pRec.cursor.valid := FALSE;
end
else
begin
pRec.cursor.entryNum := pg[VCNTLOC];
end;
end;
end;
SaveFileParameters(iFName,fId,pRec,SizeOf(pRec));
if BTreeErrorOccurred then Exit;
end;
UsingCursorGetPrevLr := LrNumToReturn(pg,pRec);
end; (* end of UsingCursorGetPrevLr routine *)
(* This routine will not move the cursor. It will return the logical record
number associated with the current cursor position. It will return 0 only
if the current cursor position is not valid. *)
function UsingCursorGetCurrLr(iFName : FnString;
var fId : File (* var for speed only *)
) : LrNumber;
var
pRec : ParameterRecord;
pg : SinglePage;
begin
FetchFileParameters(iFName,fId,pRec,SizeOf(pRec));
if BTreeErrorOccurred then Exit;
if pRec.cursor.valid then
begin
FetchPage(iFName,fId,pRec.cursor.prNum,pg);
if BTreeErrorOccurred then Exit;
end;
UsingCursorGetCurrLr := LrNumToReturn(pg,pRec);
end; (* end of UsingCursorGetCurrLr routine *)
(* This routine will not move the cursor. It will return the index entry
(data value) associated with the current cursor position. If the current
cursor position is not valid, paramValue will be returned unchanged. You
can use UsingCursorGetCurrLr to check the cursor before calling this
routine, if desired. *)
procedure UsingCursorGetCurrValue(iFName : FnString;
var fId : File; (* var for speed only *)
var paramValue);
var
pRec : ParameterRecord;
pg : SinglePage;
begin
FetchFileParameters(iFName,fId,pRec,SizeOf(pRec));
if BTreeErrorOccurred then Exit;
if pRec.cursor.valid then
begin
FetchPage(iFName,fId,pRec.cursor.prNum,pg);
if BTreeErrorOccurred then Exit;
Move(pg[((pRec.cursor.entryNum - 1) * (pRec.vSize + RNSIZE)) +
(1 + RNSIZE)],
paramValue,
pRec.vSize);
end;
end; (* end of UsingCursorGetCurrValue routine *)
(* This routine will allow you to save a cursor in memory. The current state
of the cursor will be passed back to you in the parameter cursor. It is
handy if you want to keep track of where you are in a list or check values
associated with a cursor. *)
procedure GetCursorState(iFName : FnString;
var fId : File; (* var for speed only *)
var cursor : TreeCursor);
var
pRec : ParameterRecord;
begin
FetchFileParameters(iFName,fId,pRec,SizeOf(pRec));
if BTreeErrorOccurred then Exit;
cursor := pRec.cursor;
end; (* end of GetCursorState routine *)
(*****************************************************************************)
(* *)
(* B T R E E M I S C R O U T I N E S *)
(* *)
(*****************************************************************************)
(* This routine will create an index file with the file name as specified
by iFName. The valSize parameter specifies the size of the index
entries. The easiest way to determine this is to use the SizeOf
function. The valType parameter specifies the type for the index
entries. The types supported are those enumerated by the ValueType
enumerated type.
note - Extremely important - WARNING - for STRINGVALUE indexes only - the
valSize must be 1 greater than the number of characters of the longest
string. This will allow 1 byte for the string length to be stored.
for example - if 'abc' is the longest string then valSize = 4. *)
procedure CreateIndexFile(iFName : FnString;
var fId : File;
valSize : VSizeType;
valType : ValueType;
indexedField : Integer;
upperCase : Boolean);
var
pRec : ParameterRecord;
pg : SinglePage;
begin
ReleaseAllPages(iFName);
FillChar(pg,PAGESIZE,0);
StorePage(iFName,fId,0,pg); (* parameter record *)
if BTreeErrorOccurred then Exit;
StorePage(iFName,fId,1,pg); (* bitmap record *)
if BTreeErrorOccurred then Exit;
FetchFileParameters(iFName,fId,pRec,SizeOf(pRec));
if BTreeErrorOccurred then Exit;
pRec.version := VERSIONINFO;
pRec.nextAvail := 1;
pRec.firstBMRec := 1;
pRec.lastBMRec := 1;
pRec.vSize := valSize;
pRec.rNode := CreatedNode(iFName,fId,NULL,NULL,INDEXNODE,pRec);
(* create root *)
if BTreeErrorOccurred then Exit;
pRec.fSNode := NULL;
pRec.lSNode := NULL;
pRec.fSNode := CreatedNode(iFName,fId,NULL,NULL,SEQUENCENODE,pRec);
(* create first Sequence node *)
if BTreeErrorOccurred then Exit;
FetchPage(iFName,fId,pRec.rNode,pg); (* get root page *)
if BTreeErrorOccurred then Exit;
Move(pRec.fSNode,pg[1],RNSIZE); (* put seq node in root *)
StorePage(iFName,fId,pRec.rNode,pg); (* store the root *)
if BTreeErrorOccurred then Exit;
pRec.vType := valType;
pRec.cursor.prNum := 0;
pRec.cursor.entryNum := 0;
pRec.cursor.valid := FALSE;
pRec.iField := indexedField;
pRec.UpperCaseFlag := upperCase;
SaveFileParameters(iFName,fId,pRec,SizeOf(pRec)); (* write parameters
back to buffer *)
end; (* end of CreateIndex routine *)
(*\*)
(* This routine will insert a value and its associated logical record number
into the given index file. This routine will guard against duplicate
entries. An index should have no more than one occurence of any
lrNum,paramValue pair (no two entries match on paramValue and lrNum). This
routine assures this by calling DeleteValueFromBTree prior to performing
the insert. This will get rid of a previous occurence if it exists. *)
procedure InsertValueInBTree(iFName : FnString;
var fId : File; (* var for speed only *)
lrNum : LRNumber;
var paramValue);
var
lowerNode : PrNumber;
pRec : ParameterRecord;
lowerPage,
pg: SinglePage; (* used for root and first seq node pages *)
lastValLoc : PageRange; (* used to hold buffer position *)
nextNode : NodePtrType; (* needed for inserting on root split *)
begin
{ DeleteValueFromBTree(iFName,lrNum,paramValue); (* ensure no duplicates *)}
FetchFileParameters(iFName,fId,pRec,SizeOf(pRec));
if BTreeErrorOccurred then Exit;
lowerNode := InsertValue(iFName,fId,lrNum,paramValue,pRec.rNode,pRec);
if BTreeErrorOccurred then Exit;
if lowerNode <> NULL then
begin (* we need to create a new root *)
pRec.rNode := CreatedNode(iFName,fId,NULL,NULL,INDEXNODE,pRec);
(* root has no siblings *)
if BTreeErrorOccurred then Exit;
FetchPage(iFName,fId,pRec.rNode,pg); (* get root node *)
if BTreeErrorOccurred then Exit;
FetchPage(iFName,fId,lowerNode,lowerPage); (* get child node *)
if BTreeErrorOccurred then Exit;
lastValLoc := (((lowerPage[VCNTLOC] - 1)
* ( pRec.vSize + RNSIZE)) + RNSIZE) + 1;
Move(lowerPage[NEXTLOC],pg[1],RNSIZE);
(* insert ptr for right child *)
Move(pg[1],nextNode,RNSIZE);
InsertValueIntoNode(pg, (* insert child into root *)
lowerPage[lastValLoc],
lowerNode,nextNode,pRec);
StorePage(iFName,fId,pRec.rNode,pg);
if BTreeErrorOccurred then Exit;
end;
SaveFileParameters(iFName,fId,pRec,SizeOf(pRec));
end; (* end of InsertValueInBTree routine *)
(* This routine will delete a value and its associated logical record number
from a given index file. Only the entry with the matching paramValue and
the matching logical record number will be deleted. *)
procedure DeleteValueFromBTree(iFName : FnString;
var fId : File; (* var for speed only *)
lrNum : LrNumber;
var paramValue);
var
pRec : ParameterRecord;
last,
nodeDeleted : Boolean;
begin
FetchFileParameters(iFName,fId,pRec,SizeOf(pRec));
if BTreeErrorOccurred then Exit;
if DeleteValue(iFName,fId,lrNum,paramValue,
pRec.rNode,pRec,last,nodeDeleted) then ;
if BTreeErrorOccurred then Exit;
SaveFileParameters(iFName,fId,pRec,SizeOf(pRec));
end; (* end of DeleteValueFromBTree *)
(*\*)
(* This routine will start at the root node and return the number of levels
that exist in a BTree. The index file name is the only required input. *)
function NumberOfBTreeLevels(iFName : FnString;
var fId : File (* var for speed only *)
) : Byte;
var
pRec : ParameterRecord;
pg : SinglePage;
function CountLevels(thisNode : NodePtrType) : Byte;
var
lowerNode : NodePtrType;
begin
FetchPage(iFName,fId,thisNode,pg);
if BTreeErrorOccurred then Exit;
case NodeType(pg[NTYPELOC]) of
INDEXNODE :
begin
Move(pg,lowerNode,RNSIZE);
CountLevels := CountLevels(lowerNode) + 1;
end;
SEQUENCENODE :
begin
CountLevels := 1;
end;
end; (* end of case statement *)
end; (* end of CountLevels routine *)
begin
FetchFileParameters(iFName,fId,pRec,SizeOf(pRec));
if BTreeErrorOccurred then Exit;
NumberOfBTreeLevels := CountLevels(pRec.rNode);
end; (* end of NumberOfBTreeLevels routine *)
(*\*)
(* This routine will search an index and determine whether the given logical
record number is in the index. If it is, TRUE is returned in found and the
value associated with the logical record number is returned in paramValue.
If it is not found, found will be returned as FALSE and paramValue will
remain unchanged. This is primarily used for debugging or determining if
an index has somehow been damaged. *)
procedure FindLrNumInBTree(iFName : FnString;
var fId : File; (* var fpr speed only *)
lrNum : LrNumber;
var paramValue;
var found : Boolean);
var
pRec : ParameterRecord;
pg : SinglePage;
tempLrNum : LrNumber;
node : NodePtrType;
cnt,
vCnt : Byte;
bytePtr : PageRange;
begin
FetchFileParameters(iFName,fId,pRec,SizeOf(pRec));
if BTreeErrorOccurred then Exit;
node := pRec.fSNode;
found := FALSE;
while node <> NULL do
begin
FetchPage(iFName,fId,node,pg);
if BTreeErrorOccurred then Exit;
vCnt := pg[VCNTLOC];
cnt := 1;
bytePtr := 1;
while cnt <= vCnt do
begin
Move(pg[bytePtr],tempLrNum,RNSIZE);
if tempLrNum = lrNum then
begin
found := TRUE;
Move(pg[bytePtr + RNSIZE],paramValue,pRec.vSize);
Exit;
end
else
begin
Inc(cnt);
if cnt <= vCnt then
begin (* required to keep bytePtr in range *)
bytePtr := bytePtr + RNSIZE + pRec.vSize;
end;
end;
end;
Move(pg[NEXTLOC],node,RNSIZE); (* set up to get next node *)
end;
end; (* end of FindLrNumInBTree routine *)
(*\*)
(* This routine will return a count of the number of entries in the index. *)
function IndexEntryCount(iFName : FnString;
var fId : File (* var for speed only *)
) : LrNumber;
var
pRec : ParameterRecord;
cnt,
node : NodePtrType;
pg : SinglePage;
begin
FetchFileParameters(iFName,fId,pRec,SizeOf(pRec));
if BTreeErrorOccurred then Exit;
cnt := 0;
node := pRec.fSNode;
while node <> NULL do
begin
FetchPage(iFName,fId,node,pg);
if BTreeErrorOccurred then Exit;
cnt := cnt + pg[VCNTLOC];
Move(pg[NEXTLOC],node,RNSIZE);
end;
IndexEntryCount := cnt;
end; (* end of IndexEntryFCount routine *)
(*\*)
(* This routine will print out information regarding the index file. It is
designed to aid in my debugging, but is available for your use as well.
The nodeInfo paramter is used to specify whether you want the information
for each node in the index to be printed. *)
procedure PrintBTreeInfo(iFName : FnString;
var fId : File; (* var for speed only *)
nodeInfo : Boolean;
var lst : PrintTextDevice);
const
LEVEL = 0;
var
pRec : ParameterRecord;
pg : SinglePage;
(* Print information for each node for this level *)
procedure PrintLevelInfo(thisNode : NodePtrType;
level : Byte);
var
lowerNode : NodePtrType;
first : Boolean;
s : String[8];
begin
Inc(level);
Writeln(lst);
Writeln(lst,'Node Information for level ',level);
first := TRUE;
while thisNode <> 0 do
begin
FetchPage(iFName,fId,thisNode,pg);
if BTreeErrorOccurred then Exit;
if first then
begin
first := FALSE;
Move(pg,lowerNode,RNSIZE);
end;
Writeln(lst);
Write(lst,' Number of entries = ',pg[VCNTLOC]);
Write(lst,' Physical Record Number = ',thisNode);
case NodeType(pg[NTYPELOC]) of
INVALIDNODETYPE : s := 'INVALID';
INDEXNODE : s := 'INDEX';
SEQUENCENODE : s := 'SEQUENCE';
else s := 'ERROR';
end;
Writeln(lst,' Node Type = ',s);
Writeln(lst,' Lowest Value in Node = ',
ConvertValueToString(pg[RNSIZE + 1],pRec.vType));
Writeln(lst,' Highest Value in node = ',
ConvertValueToString(pg[((RNSIZE + pRec.vSize) *
(pg[VCNTLOC] -1)) + RNSIZE + 1],
pRec.vType));
Move(pg[NEXTLOC],thisNode,RNSIZE);
end;
if NodeType(pg[NTYPELOC]) = INDEXNODE then
begin
PrintLevelInfo(lowerNode,level);
end;
end;
begin
FetchFileParameters(iFName,fId,pRec,SizeOf(pRec));
if BTreeErrorOccurred then Exit;
Writeln(lst);
Writeln(lst,'The following is index file information');
Writeln(lst,'Index File Name = ',iFName);
Writeln(lst,'Next Available Node (physical record) = ',pRec.nextAvail);
Writeln(lst,'First Bitmap Record = ',pRec.firstBMRec);
Writeln(lst,'Last Bitmap Record = ',pRec.lastBMRec);
Writeln(lst,'Size of each index entry = ',pRec.vSize);
Writeln(lst,'Type of each index entry = ',Byte(pRec.vType));
Writeln(lst,'Maximum index entries per node = ',MaxEntries(pRec.vSize));
Writeln(lst,'Total number of index entries = ',IndexEntryCount(iFName,fId));
if BTreeErrorOccurred then Exit;
Writeln(lst,'Root Node = ',pRec.rNode);
Writeln(lst,'First Sequence Node = ',pRec.fSNode);
Writeln(lst,'Last Sequence Node = ',pRec.lSNode);
Writeln(lst,'Number of levels = ',NumberOfBTreeLevels(iFName,fId));
if BTreeErrorOccurred then Exit;
if nodeInfo then
begin
PrintLevelInfo(pRec.rNode,level);
end;
Writeln(lst);
end; (* end of PrintBTreeInfo routine *)
(* This routine returns the field number of the indexed field in support of
GoldDB *)
function GetIndexedField(iFName : FnString;
var fId : File) : Integer; (* var for speed only *)
var
pRec : ParameterRecord;
begin
FetchFileParameters(iFName,fId,pRec,SizeOf(pRec));
if BTreeErrorOccurred then Exit;
GetIndexedField := pRec.iField;
end; (* end of GetIndexedField routine *)
(* This function returns the record number corresponding to the given entry
number. An entry number is the relative number from the beginning of the
index. In other words, entry number one is the first entry in the index.
It will return NULL if there is no corresponding record number. This can
only happen if entryNum > number of entries in the index. *)
function GetBTreeEntryLR(iFName : FnString;
var fId : File; (* var for speed only *)
entryNum : LrNumber) : LrNumber;
var
pRec : ParameterRecord;
tempLr,
cnt : LrNumber;
node : NodePtrType;
pg : SinglePage;
done : Boolean;
bytePtr : PageRange;
begin
FetchFileParameters(iFName,fId,pRec,SizeOf(pRec));
if BTreeErrorOccurred then Exit;
cnt := 0;
node := pRec.fSNode;
done := FALSE;
while not done do
begin
FetchPage(iFName,fId,node,pg);
if BTreeErrorOccurred then Exit;
cnt := cnt + pg[VCNTLOC];
if entryNum <= cnt then
begin
cnt := cnt - pg[VCNTLOC];
bytePtr := ((RNSIZE + pRec.vSize) * ((entryNum - cnt) - 1)) + 1;
Move(pg[bytePtr],tempLr,RNSIZE);
done := TRUE;
end
else
begin
Move(pg[NEXTLOC],node,RNSIZE);
if node = NULL then
begin
done := TRUE;
tempLr := NULL;
end;
end;
end;
GetBTreeEntryLR := tempLr;
end; (* end of GetBTreeEntryLR routine *)
(* This routine returns TRUE if the index is all upper case *)
function GetUpperCaseFlag(iFName : FnString;
var fId : File) : Boolean; (* var for speed only *)
var
pRec : ParameterRecord;
begin
FetchFileParameters(iFName,fId,pRec,SizeOf(pRec));
if BTreeErrorOccurred then Exit;
GetUpperCaseFlag := pRec.upperCaseFlag;
end; (* end of GetIndexedField routine *)
(* This routine will perform a partial or a full validation of an index file.
(depending on the value of the variable Partial). A partial check will
validate that the pRec record (record 0) is intact and that the file
structure is valid. A full validation will perform an additional check
to ensure that the data file and the index file are synchronized. The
routine will return one of the following values:
0 : No errors
-1 : Header error
-2 : File error
-3 : Index and dat files not synchronized *)
function ValidateBTree(iFName : FnString;
var fId : File (* var for speed only *)
): ValidationError;
var
pRec : ParameterRecord;
result : ValidationError;
function NodeInUse(thisNode : NodePtrType) : Boolean;
begin
NodeInUse := CheckBitInBitmap(iFName,fId,pRec.firstBMRec,thisNode);
end;
function CheckVSizeAndVType : Boolean;
begin
if (pRec.vSize < 1) or (pRec.vSize > MAXVALSIZE) then
begin
CheckVSizeAndVType := FALSE;
end
else
begin
if pRec.vType = STRINGVALUE then
begin
CheckVSizeAndVType := TRUE;
end
else
begin
CheckVSizeAndVType := ((GetSizeFromVType(pRec.vType)
= pRec.vSize));
end;
end;
end;
begin
FetchFileParameters(iFName,fId,pRec,SizeOf(pRec));
if BTreeErrorOccurred then Exit;
if prec.version <> VERSIONINFO then
begin
ValidateBTree := PRECERROR;
Exit;
end;
if (pRec.firstBMRec = NULL) or (pRec.lastBMRec = NULL) then
begin
ValidateBTree := PRECERROR;
Exit;
end;
if NodeInUse(pRec.nextAvail) then
begin
ValidateBTree := PRECERROR;
Exit;
end;
if BTreeErrorOccurred then Exit;
if not NodeInUse(pRec.rNode) then
begin
ValidateBTree := PRECERROR;
Exit;
end;
if BTreeErrorOccurred then Exit;
if not NodeInUse(pRec.fSNode) then
begin
ValidateBTree := PRECERROR;
Exit;
end;
if BTreeErrorOccurred then Exit;
if not NodeInUse(pRec.lSNode) then
begin
ValidateBTree := PRECERROR;
Exit;
end;
if BTreeErrorOccurred then Exit;
if (pRec.vType <= INVALIDVALUE) or (pRec.vtype > BYTEARRAYVALUE) then
begin
ValidateBTree := PRECERROR;
Exit;
end;
if not CheckVSizeAndVType then
begin
ValidateBTree := PRECERROR;
end
else
begin
ValidateBTree := NOERROR;
end;
end; (* end of ValidateBTree routine *)